package gl.web.onlinedoc.search;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.search.highlight.SimpleSpanFragmenter;
import org.apache.lucene.search.highlight.TokenSources;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

/**
 *
 */
public class SearchManager {
	private static SearchManager indexManager;

	private static String indexSaveDir = null;
//	public static String DATA_DIR = "D:\\luceneData";
	private static Analyzer analyzer = null;
	private static Directory directory = null;
	private static IndexWriter indexWriter = null;
	private static HashSet<String> SearchableFileType = new HashSet<String>();
	static {
		SearchableFileType.add(".txt");
		SearchableFileType.add(".html");
	}

	/**
	 * 创建索引管理器
	 * 
	 * @return 返回索引管理器对象
	 */
	public SearchManager getManager() {
		if (indexManager == null) {
			indexManager = new SearchManager();
		}
		return indexManager;
	}

	/**
	 * 重新创建当前文件目录的索引
	 * 
	 * @param path
	 *            当前文件目录
	 * @return 是否成功
	 */
	public static boolean createIndex(String path,String indexSavePath) {
		indexSaveDir = indexSavePath;
		File fileIndex = new File(indexSaveDir);
		if (deleteDir(fileIndex)) {
			fileIndex.mkdir();
		} else {
			fileIndex.mkdir();
		}
		
		List<File> fileList = getFileList(path);
		for (File file : fileList) {
			String content = "";
			// 获取文件后缀
			String type = file.getName().substring(
					file.getName().lastIndexOf(".") + 1);
			// System.out.println("type :" + type);
			if ("txt".equalsIgnoreCase(type)) {

				content += txt2String(file);

			} else if ("html".equalsIgnoreCase(type)) {

				content += txt2String(file);

			}

			 System.out.println("name :" + file.getName());
			// System.out.println("path :" + file.getPath());
			// System.out.println("content :"+content);
			// System.out.println();

			try {
				analyzer = new StandardAnalyzer();
				directory = FSDirectory.open(Paths.get(indexSavePath));

				File indexFile = new File(indexSavePath);
				if (!indexFile.exists()) {
					indexFile.mkdirs();
				}
				IndexWriterConfig config = new IndexWriterConfig(analyzer);
				indexWriter = new IndexWriter(directory, config);

				Document document = new Document();
				document.add(new TextField("filename", file.getName(),
						Store.YES));
				document.add(new TextField("content", content, Store.YES));
				document.add(new TextField("path", file.getPath(), Store.YES));
				indexWriter.addDocument(document);
				indexWriter.commit();
				closeWriter();

			} catch (Exception e) {
				e.printStackTrace();
			}
			content = "";
		}
		// Date date2 = new Date();
		// System.out.println("创建索引-----耗时：" + (date2.getTime() -
		// date1.getTime())
		// + "ms\n");
		return true;
	}

	/**
	 * 读取txt文件的内容
	 * 
	 * @param file
	 *            想要读取的文件对象
	 * @return 返回文件内容
	 */
	public static String txt2String(File file) {
		String result = "";
		try {
			BufferedReader br = new BufferedReader(new FileReader(file));// 构造一个BufferedReader类来读取文件
			String s = null;
			while ((s = br.readLine()) != null) {// 使用readLine方法，一次读一行
				result = result + "\n" + s;
			}
			br.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 查找索引，返回符合条件的文件
	 * 
	 * @param text
	 *            查找的字符串
	 * @return 符合条件的文件List
	 */
	public static List<SearchResult> searchIndex(String text) {
		List<SearchResult> resultList = new ArrayList<SearchResult>();
		if (text==null||text.length()<=0) {
			return resultList; 
		}
		System.out.println("search keyword:" + text);
		try {
			directory = FSDirectory.open(Paths.get(indexSaveDir));
			analyzer = new StandardAnalyzer();
			DirectoryReader ireader = DirectoryReader.open(directory);
			IndexSearcher isearcher = new IndexSearcher(ireader);

			QueryParser parser = new QueryParser("content", analyzer);
			Query query = parser.parse(text);

			ScoreDoc[] hits = isearcher.search(query, 1000).scoreDocs;

			for (int i = 0; i < hits.length; i++) {
				SearchResult result = new SearchResult();
				final ScoreDoc scoreDoc = hits[i];
				final Document hitDoc = isearcher.doc(scoreDoc.doc);
				final String hight = highlightSearcher(isearcher, query,
						scoreDoc, hitDoc);
				System.out.println("____________________________");
				System.out.println(hitDoc.get("filename"));
				System.out.println(hitDoc.get("content"));
				System.out.println(hitDoc.get("path"));
				System.out.println(hight);
				System.out.println("____________________________");

				result.filepath = hitDoc.get("filename");
				result.highLight = hight;
				resultList.add(result);
			}
			ireader.close();
			directory.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		// System.out.println("查看索引-----耗时：" + (date2.getTime() -
		// date1.getTime())
		// + "ms\n");
		return resultList;
	}

	public static String highlightSearcher(IndexSearcher isearcher,
			Query query, final ScoreDoc scoreDoc, final Document hitDoc)
			throws IOException, InvalidTokenOffsetsException {
		QueryScorer scorer = new QueryScorer(query, "content");

		Formatter formatter = new SimpleHTMLFormatter(
				"<b><font color='#ff9955' size='5'>", "</font></b>");
		Highlighter highlighter = new Highlighter(formatter, scorer);

		highlighter.setTextFragmenter(new SimpleSpanFragmenter(scorer));
		final IndexReader indexReader = isearcher.getIndexReader();
		@SuppressWarnings("deprecation")
		TokenStream tokenStream = TokenSources.getAnyTokenStream(indexReader,
				scoreDoc.doc, "content", hitDoc, analyzer);
		final String hight = highlighter.getBestFragment(tokenStream,
				hitDoc.get("content"));
		tokenStream.close();
		return hight;
	}

	/**
	 * 过滤目录下的文件
	 * 
	 * @param dirPath
	 *            想要获取文件的目录
	 * @return 返回文件list
	 */
	public static List<File> getFileList(String dirPath) {
		File[] files = new File(dirPath).listFiles();
		List<File> fileList = new ArrayList<File>();
		for (File file : files) {
			if (isSupportFile(file.getName())) {
				fileList.add(file);
			}
		}
		return fileList;
	}

	/**
	 * 判断是否为目标文件
	 * 
	 * @see FileType
	 * 
	 * @param fileName
	 *            文件名称
	 * @return 如果是文件类型满足过滤条件，返回true；否则返回false
	 */
	public static boolean isSupportFile(String fileName) {
		if (fileName.lastIndexOf(".") < 0) {
			return false;
		}
		return SearchableFileType.contains(fileName.substring(fileName
				.lastIndexOf(".")));
	}

	public static void closeWriter() throws Exception {
		if (indexWriter != null) {
			indexWriter.close();
		}
	}

	/**
	 * 删除文件目录下的所有文件
	 * 
	 * @param file
	 *            要删除的文件目录
	 * @return 如果成功，返回true.
	 */
	public static boolean deleteDir(File file) {
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			for (int i = 0; i < files.length; i++) {
				deleteDir(files[i]);
			}
		}
		file.delete();
		return true;
	}

	public static void main(String[] args) throws IOException,
			InvalidTokenOffsetsException {
		String DATA_DIR = "G:\\doc\\gamepad\\sdk\\doc";
		String INDEX_DIR = "G:/";
		System.out.println(INDEX_DIR);


		createIndex(DATA_DIR,INDEX_DIR);
		List<SearchResult> docSearchResults = searchIndex("href");
		for (int i = 0; i < docSearchResults.size(); i++) {
			System.out.println("_________________");
			System.out.println("File :" + docSearchResults.get(i).filepath);
			System.out.println("Info :" + docSearchResults.get(i).highLight);
			System.out.println("_________________");
		}
	}
}